package etilan.Client;
import java.util.List;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.AlertDialog;
import android.app.Dialog;
import android.bluetooth.BluetoothAdapter;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.hardware.Sensor;
import android.hardware.SensorManager;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiManager.WifiLock;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.preference.PreferenceManager;
import android.provider.Settings;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import etilan.Client.R;

public class MainActivity extends Activity{
	private Button startit, startb;
	private Intent i, j;
	private TextView ontext, context, iptext, ipNWtext, localiptext, localwifitext,localbluetoothtext;
	private MainService apsbound = null;
	private ActivityManager am;
	private boolean running;
	private String ipT;
	private WifiLock wL;
	private SharedPreferences prefs;
	private Menu mainMenu;
	WifiManager wm;
	private String bluetoothAddress;
	private static final int DIALOG_ID_NO_ACCEL = 1;
	public static final int PURPOSE_SETUP = 1;
	public static final int PURPOSE_CALIBRATE = 2;
	// Message types sent from the BluetoothChatService Handler
    public static final int MESSAGE_STATE_CHANGE = 1;
    public static final int MESSAGE_READ = 2;
    public static final int MESSAGE_WRITE = 3;
    public static final int MESSAGE_DEVICE_NAME = 4;
    public static final int MESSAGE_TOAST = 5;
    // Key names received from the BluetoothChatService Handler
    public static final String DEVICE_NAME = "device_name";
    public static final String TOAST = "toast";
    // Intent request codes
    private static final int REQUEST_CONNECT_DEVICE = 1;
	
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        prefs = PreferenceManager.getDefaultSharedPreferences(this);
        startit = (Button)findViewById(R.id.Startit);
        startit.setOnClickListener(cl);
        startb = (Button)findViewById(R.id.LaunchButtons);
        startb.setOnClickListener(cl);
        ontext = (TextView)findViewById(R.id.Ontext);
        context = (TextView)findViewById(R.id.Context);
        iptext = (TextView)findViewById(R.id.IPText);
        ipNWtext = (TextView)findViewById(R.id.NWifiIPText);
        localiptext = (TextView)findViewById(R.id.LocalIPText);
        localwifitext = (TextView)findViewById(R.id.LocalWifiText);
        localbluetoothtext=(TextView)findViewById(R.id.LocalBluetoothText);
        i = new Intent(MainActivity.this,MainService.class);
        j = new Intent(MainActivity.this,JoystickActivity.class);
        am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
        
		startb.setEnabled(false);
        
        SensorManager sm = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
        if(sm.getSensorList(Sensor.TYPE_ACCELEROMETER).isEmpty()){
        	showDialog(DIALOG_ID_NO_ACCEL);
        	startit.setEnabled(false);
			Log.i("DroidPad", "DP: No accelerometer!");
        }
        if(isRunning("MainService")){
			Log.v("DroidPad", "DP: DPS already running");
        	startit.setText("Stop");
	        ontext.setText("Status: On");
			startb.setEnabled(true);
	        bind();
	        running = true;
        }
        else{
        	startit.setText("Start");
	        running = false;
        }

        wm = (WifiManager) getSystemService(Context.WIFI_SERVICE);
        wL = wm.createWifiLock(WifiManager.WIFI_MODE_FULL, "DroidPad");
		wL.acquire();
        IntentFilter wifiFilter = new IntentFilter();
        wifiFilter.addAction(WifiManager.NETWORK_IDS_CHANGED_ACTION);
        wifiFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
        wifiFilter.addAction(WifiManager.RSSI_CHANGED_ACTION);
        wifiFilter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
        wifiFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);
        wifiFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
        registerReceiver(wifiListener, wifiFilter);
        wifiState();
        wifiConn();
        
        if(isRunning("JoystickActivity"))
        	startActivity(j);
    }
    
    public OnClickListener cl = new OnClickListener(){
		@Override
		public void onClick(View v) {
			switch(v.getId()){
			case R.id.Startit:
				if(!running){
					Log.i("DroidPad", "DP: Starting DroidPad");
					i = new Intent(MainActivity.this, MainService.class);
					i.putExtra("purpose", PURPOSE_SETUP);
					try{
						i.putExtra("interval", Integer.parseInt(prefs.getString("updateinterval", "20")));
					}
					catch (NumberFormatException e){
						Toast.makeText(getBaseContext(), "In Preferences, \"Update Interval\" is not a number!", Toast.LENGTH_LONG).show();
						Log.w("DroidPad", "DP: Number format error");
						return;
					}
					
					try{
						i.putExtra("port", Integer.parseInt(prefs.getString("portnumber", "3141")));
					}
					catch (NumberFormatException e)
					{
						Toast.makeText(getBaseContext(), "In Preferences, \"Port\" is not a number!", Toast.LENGTH_LONG).show();
						Log.w("DroidPad", "DP: Number format error");
						return;
					}
					Log.v("DroidPad", "DP: Starting DPS service");
					startService(i);
					Log.v("DroidPad", "DP: DPS service started! (will start when loop is free)");
					startit.setText("Stop");
					startb.setEnabled(true);
					ontext.setText("Status: On");
					bind();
					Log.v("DroidPad", "DP: Bound to service");
					running = true;
					/*if(mainMenu != null)
					{
						mainMenu.getItem(1).setEnabled(false);
			    		mainMenu.getItem(2).setEnabled(true);
					}*/
				}
		        else{
					Log.i("DroidPad", "DP: Stopping DroidPad");
		        	sendParentKill();
		        	unbind();
		        	i = new Intent(MainActivity.this, MainService.class);
		        	stopService(i);
					Log.v("DroidPad", "DP: Sucessfully killed DPS");
		        	startit.setText("Start");
					startb.setEnabled(false);
		        	ontext.setText("Status: Off");
		        	context.setText("Not Connected");
		        	iptext.setText("");
		        	ipNWtext.setText("");
		        	ipT = "";
					running = false;
					/*if(mainMenu != null)
					{
						mainMenu.getItem(1).setEnabled(true);
						mainMenu.getItem(2).setEnabled(false);
					}*/
		        }
				break;
			case R.id.LaunchButtons:
				startActivity(j);
				break;
			}
		}
    };
    
    public boolean onCreateOptionsMenu(Menu menu){
    	MenuInflater inflater = getMenuInflater();
    	inflater.inflate(R.menu.menu, menu);
    	menu.getItem(0).setIcon(R.drawable.wifiicon);
    	menu.getItem(1).setIcon(android.R.drawable.ic_menu_preferences);
    	menu.getItem(2).setIcon(R.drawable.options);
    	//menu.getItem(2).setEnabled(running);
    	menu.getItem(3).setIcon(android.R.drawable.ic_menu_info_details);
    	mainMenu = menu;
		return true;
    }
    
    public boolean onOptionsItemSelected(MenuItem item){
    	if (!item.hasSubMenu()){
    		Intent i;
    		switch (item.getItemId()){
    		
    		 case R.id.scan:
    	            // Launch the DeviceListActivity to see devices and do scan
    	            Intent serverIntent = new Intent(this, BlueDeviceListActivity.class);
    	            startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE);
    	            return true;
    		
    		case R.id.wifi:
    			i = new Intent(Settings.ACTION_WIFI_SETTINGS);
    			try{
    				startActivity(i);
    			}
    			catch (ActivityNotFoundException a){
    				Toast.makeText(getBaseContext(), "Could not launch Wifi settings.", Toast.LENGTH_SHORT).show();
    			}
    			break;
    		case R.id.settings:
    			i = new Intent(MainActivity.this,SettingsMenu.class);
    			startActivity(i);
    			break;
    		case R.id.calibrate:
    			i = new Intent(MainActivity.this, MainService.class);
				i.putExtra("purpose", PURPOSE_CALIBRATE);
				startService(i);
				break;
    		}
    	}
		return true;
    }
    
    @Override 
    protected Dialog onCreateDialog(int id) { 
        if(id == DIALOG_ID_NO_ACCEL){
            return new AlertDialog.Builder(MainActivity.this)
            .setTitle("ERROR: Accelerometer not found!")
            .setPositiveButton("OK",new DialogInterface.OnClickListener()
            { 
                public void onClick(DialogInterface dialog, int which){
                	finish();
                }
            }
            ) 
            .create(); 
        }
        return null; 
      } 
    
    private BroadcastReceiver wifiListener = new BroadcastReceiver() {
        @Override
        public void onReceive(Context c, Intent i){
        final String action = i.getAction();
        if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION))
            wifiConn();
        else if (action.equals(WifiManager.RSSI_CHANGED_ACTION))
            wifiConn();
        else if (action.equals(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION))
            wifiConn();
        else if (action.equals(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION))
            wifiConn();
        else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION))
        	wifiState();
        }
    };
    
    private void wifiState(){
        switch (wm.getWifiState()){
        case WifiManager.WIFI_STATE_DISABLED:
            localwifitext.setText("Disabled");
            localiptext.setVisibility(View.INVISIBLE);
            break;
        case WifiManager.WIFI_STATE_DISABLING:
            localwifitext.setText("Disabling");
           
            localiptext.setVisibility(View.INVISIBLE);
            updateIPT(false);
            break;
        case WifiManager.WIFI_STATE_ENABLED:
            localwifitext.setText("Enabled");
            localiptext.setVisibility(View.VISIBLE);
            updateIPT(true);
            break;
        case WifiManager.WIFI_STATE_ENABLING:
            localwifitext.setText("Enabling");
            localiptext.setVisibility(View.INVISIBLE);
            break;
        case WifiManager.WIFI_STATE_UNKNOWN:
            localwifitext.setText("not supported!");
            break;
        }
        localwifitext.setText("Wifi: " + localwifitext.getText());
        BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        if (mBluetoothAdapter.getState()==BluetoothAdapter.STATE_OFF)
        	localbluetoothtext.setText("Bluetooth: Disabled" );
        else
        	localbluetoothtext.setText("Bluetooth: Enabled" );
    }
    
    private void wifiConn(){
        switch (wm.getConnectionInfo().getSupplicantState()){
        case ASSOCIATED:
            // Association completed.
            localiptext.setText("Connecting");
            break;
        case ASSOCIATING:
            // Trying to associate with a BSS/SSID. 
            localiptext.setText("Connecting");
            break;
        case COMPLETED:
            // All authentication completed. 
            // Trying to associate with a BSS/SSID.
        	int ip = wm.getConnectionInfo().getIpAddress();
        	
        	if(ip != 0)
        		localiptext.setText("IP: " + ipTextFromByte(ipFromInt(ip)));
        	else
        		localiptext.setText("Connecting");
            
            break;
        case DISCONNECTED:
            // This state indicates that client is not associated, but is
            // likely to start looking for an access point.
            localiptext.setText("");
            break;
        case DORMANT:
            // An Android-added state that is reported when a client issues an explicit DISCONNECT command.
            localiptext.setText("");
            break;
        case FOUR_WAY_HANDSHAKE:
        case GROUP_HANDSHAKE:
            // WPA 4-Way Key Handshake in progress.
            // WPA Group Key Handshake in progress.
            localiptext.setText("Connecting");
            break;
        case INACTIVE:
            // Inactive state (wpa_supplicant disabled).
            localiptext.setText("");
            break;
        case INVALID:
            // A pseudo-state that should normally never be seen.
            localiptext.setText("");
            break;
        case SCANNING:
            // Scanning for a network.
            localiptext.setText("Scanning");
            break;
        case UNINITIALIZED:
            // No connection to wpa_supplicant.
            localiptext.setText("");
            break;
        }
    }
	
    private void bind(){
    	i = new Intent(MainActivity.this, MainService.class);
        bindService(i,mConnection,0);
    }
    
    private void unbind(){
    	if(apsbound != null)
    		unbindService(mConnection);
    }
    
    private void sendParent(){
    	if(apsbound != null)
    		apsbound.sendParentObject(this);
    }
    
    private void sendParentKill(){
    	if(apsbound != null)
    		apsbound.sendParentObject(null);
    }
    
    private boolean isRunning(String Activity){
        List<ActivityManager.RunningServiceInfo> sl = am.getRunningServices(Integer.MAX_VALUE);
        for(int i = 0;i < sl.size();i++)
        	if(sl.get(i).service.getClassName().equals("etlian.Client." + Activity))
        		return true;
        return false;
    }

    private ServiceConnection mConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className, IBinder service) {
            apsbound = ((MainService.LocalBinder)service).getService();
            sendParent();
        }

        public void onServiceDisconnected(ComponentName className) {
            apsbound = null;
        }
    };
    
    public Handler isConnectedCallback = new Handler() {
    	@Override
        public void handleMessage(Message msg) {
    		super.handleMessage(msg);
    		if(msg.arg1 == 1){
    			context.setText("Connected");
	        	if(msg.getData().getString("ip").startsWith("127"))	{
	        		ipT = "Connected via USB";
	        		updateIPT(wm.getWifiState() == WifiManager.WIFI_STATE_ENABLED);
	        	}
	        	else if(msg.getData().getString("ip") == "0.0.0.0"){
	        		ipT = "";
	        		updateIPT(wm.getWifiState() == WifiManager.WIFI_STATE_ENABLED);
	        	}
	        	else{
	        		ipT = "Remote IP: " + msg.getData().getString("ip");
	        		updateIPT(wm.getWifiState() == WifiManager.WIFI_STATE_ENABLED);
	        	}
	        	startActivity(new Intent(MainActivity.this, JoystickActivity.class));
    		}
    		else{
    			context.setText("Not Connected");
		        ipT = "";
        		updateIPT(wm.getWifiState() == WifiManager.WIFI_STATE_ENABLED);
    		}
			Log.v("DroidPad", "DP: IP text set");
    	}
    };
    
    @Override
    public void onDestroy(){
        unregisterReceiver(wifiListener);
        wL.release();
    	super.onDestroy();
    }
    
    public static final int[] ipFromInt(int value){
    	int[] b = new int[4];
    	b[0] = (value & 0xFF000000) >> 24;
    	b[1] = (value & 0x00FF0000) >> 16;
    	b[2] = (value & 0x0000FF00) >> 8;
    	b[3] = (value & 0x000000FF);
        return b;
    }
    
    public static final String ipTextFromByte(int[] ip){
    	return String.valueOf(ip[3]) + "." + String.valueOf(ip[2]) + "." + String.valueOf(ip[1]) + "." + String.valueOf(ip[0]);
    }
    
    private void updateIPT(boolean wifiOn){
    	if(wifiOn){
    		iptext.setText(ipT);
    		ipNWtext.setText("");
    	}
    	else{
    		ipNWtext.setText(ipT);
    		iptext.setText("");
    	}
    }
    
    public void onActivityResult(int requestCode, int resultCode, Intent data){
        switch (requestCode){
        case REQUEST_CONNECT_DEVICE:
            // When DeviceListActivity returns with a device to connect
            if (resultCode == Activity.RESULT_OK){
                // Get the device MAC address
                bluetoothAddress = data.getExtras().getString(BlueDeviceListActivity.EXTRA_DEVICE_ADDRESS);
                prefs = PreferenceManager.getDefaultSharedPreferences(this);
                Editor edit1=prefs.edit();
                edit1.putString("bluetoothAddress", bluetoothAddress);
                edit1.commit();
            }
            break;
        }
    }
}